home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 23 / AMIGAplus Sonderheft 23 (2000)(Falke)(DE)[!].iso / Tools / Text-Viewer / MSWordView / notes / summaryinfo / CPPSUM.ZIP / CPPSUM.CPP next >
Encoding:
C/C++ Source or Header  |  1995-03-25  |  13.0 KB  |  385 lines

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // DLL functions to get summary info from OLE 2.0 document files.
  4. //
  5. //    Copyright © 1994-1995 Somar Software, All Rights Reserved
  6. //    Send problem reports and comments to 72202.2574@compuserve.com
  7. //    Visit the Somar Software WWW site at http://www.somar.com
  8. //            
  9. // Change Log:
  10. //    V1.5 95/03/25 Handle PID_TOTAL_EDITTIME (time < 1980-01-01)
  11. //      V1.4 95/02/06 Add 32 bit version of DLL, documentation changes
  12. //    V1.3 94/06/06 Change validity checking, because Excel 5.0 files
  13. //                     are slightly invalid
  14. //    V1.2 94/03/01 Change STGM_SHARE_DENY_WRITE to STGM_SHARE_DENY_NONE, so
  15. //                     info can be obtained for files currently open in WinWord.
  16. //    V1.1 94/01/22 Add wInitStatus parameter to SumInfoInit and SumInfoUninit,
  17. //                     to account for case where CoInitialize already called for  
  18. //                     application.
  19. //                  Ensure SumInfoGetString returns zero terminated string.
  20. //                  Fix minor typos in documentation.
  21. //    V1.0 94/01/20 Initial version.
  22. //                 
  23. // Example of usage:
  24. //     WORD   wInitStatus;
  25. //     HANDLE hSumInfo;
  26. //     char   szTemp[256];
  27. //     LPSTR  szFilePath;
  28. //     WORD   yr, mon, day, hr, min, sec;
  29. //     if (wInitStatus = SumInfoInit()) {
  30. //        ... loop to process files ...
  31. //           szFilePath = ...
  32. //           if (hSumInfo = SumInfoOpenFile(szFilePath)) {
  33. //              if (SumInfoGetString(hSumInfo, PID_TITLE, szTemp, 256)) {
  34. //                 ... do something with szTemp ...
  35. //              }
  36. //              if (SumInfoGetTime(hSumInfo, PID_LASTSAVED, 
  37. //                                 &yr, &mon, &day, &hr, &min, &sec)) {
  38. //                 ... do something with time ...
  39. //              }
  40. //              ...
  41. //              SumInfoCloseFile(hSumInfo);
  42. //           }
  43. //        }
  44. //        SumInfoUninit(wInitStatus);
  45. //     }
  46. //
  47. // Reasons for failure:
  48. //     SumInfoInit:     out of memory
  49. //     SumInfoOpenFile: out of memory
  50. //                      file not found
  51. //                      file is not an OLE 2.0 structured storage file
  52. //                      file does not contain OLE 2.0 summary info
  53. //                      OLE 2.0 summary info is incorrectly formatted
  54. //     SumInfoGet...  : specified property type is not available
  55. //     
  56. ///////////////////////////////////////////////////////////////////////////
  57.  
  58. #define STRICT
  59. #include <windows.h>
  60. #include <memory.h>
  61. #ifdef WIN32
  62. #include <objbase.h>
  63. #else
  64. #include <ole2ver.h>      
  65. #include <storage.h>
  66. #include <compobj.h>
  67. #endif
  68. #pragma hdrstop
  69.  
  70. // a temporary function was unreferenced and then removed by optimization
  71. // causing warning 4505
  72. #pragma warning(disable:4505) 
  73.  
  74. ///////////////////////////////////////////////////////////////////////////
  75. #ifdef WIN32
  76. #define DLLEXPORT __stdcall
  77. #else
  78. #define DLLEXPORT FAR PASCAL __export
  79. #define VT_I4           3
  80. #define VT_LPSTR        30
  81. #define VT_FILETIME     64
  82. #endif
  83.  
  84. typedef struct _PROPVALUE {
  85.     DWORD vtType;
  86.     union {
  87.         FILETIME      vtTime;  
  88.         LONG          vtLong;
  89.         struct {
  90.             DWORD cBytes;
  91.             char  ch[1];
  92.         } vtBSTR;
  93.     } vtValue;
  94. } PROPVALUE;
  95. typedef PROPVALUE FAR * LPPROPVALUE;
  96.  
  97. typedef struct _SUMMARYINFO {
  98.     DWORD   cBytes;
  99.     DWORD   cProps;
  100.     struct {
  101.         DWORD propID;
  102.         DWORD dwOffset;
  103.     } aProps[1];
  104. } SUMMARYINFO;
  105. typedef SUMMARYINFO FAR * LPSUMINFO;
  106.  
  107. LPPROPVALUE FindProperty(HANDLE hSumInfo, DWORD pid);
  108.  
  109. ///////////////////////////////////////////////////////////////////////////
  110. extern "C" WORD DLLEXPORT SumInfoInit()
  111. {
  112. #ifndef WIN32
  113.     DWORD dwVer = CoBuildVersion();
  114.     if (rmm != HIWORD(dwVer)) return 0;
  115. #endif
  116.  
  117.     HRESULT hr = CoInitialize(NULL);
  118.     SCODE scode = GetScode(hr);
  119.     if (scode == S_OK) return 1;
  120.     if (scode == S_FALSE) return 2;
  121.     return 0;
  122. }
  123.  
  124. ///////////////////////////////////////////////////////////////////////////
  125. extern "C" void DLLEXPORT SumInfoUninit(WORD wInitStatus)
  126. {
  127. #ifndef WIN32
  128.     if (wInitStatus == 1)
  129. #endif
  130.         CoUninitialize();
  131. }   
  132.  
  133. ///////////////////////////////////////////////////////////////////////////
  134. extern "C" HANDLE DLLEXPORT SumInfoOpenFile(LPSTR szPath)
  135. {
  136.     BOOL            bResult = FALSE;
  137.     LPSUMINFO       lpSumInfo;
  138.     DWORD           i;       
  139.     DWORD           dwBytesInSection;
  140.     HRESULT         hr;
  141.     ULONG           ulBytesRead;                      
  142.     LARGE_INTEGER   li;                 
  143.     LPSTREAM        pIStream;
  144.     LPSTORAGE       pIStorage;
  145.     HGLOBAL         hglb = NULL;
  146.  
  147.     struct {
  148.         WORD     byteOrder;
  149.         WORD     wFormat;
  150.         WORD     osVersion1;
  151.         WORD     osVersion2;
  152.         CLSID    classId;
  153.         DWORD    cSections;
  154.     } PropHeader;
  155.     struct {
  156.         DWORD dwords[4];
  157.         DWORD dwOffset;
  158.     } FIDAndOffset;
  159. #ifdef WIN32
  160.     WCHAR            wzPath[MAX_PATH+1];
  161.  
  162.     if (mbstowcs(wzPath, szPath, MAX_PATH) == -1)
  163.         return NULL;
  164.     wzPath[MAX_PATH] = 0; // ensure null termination
  165.  
  166.     hr = StgOpenStorage(wzPath,
  167.                         NULL, STGM_READ | STGM_SHARE_DENY_NONE | STGM_PRIORITY,
  168.                         NULL, 0, &pIStorage);
  169.     if (FAILED(hr)) return NULL;
  170.  
  171.     hr = pIStorage->OpenStream(L"\005SummaryInformation", NULL,
  172.                         STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  173. #else
  174.     hr = StgOpenStorage(szPath,
  175.                         NULL, STGM_READ | STGM_SHARE_DENY_NONE | STGM_PRIORITY,
  176.                         NULL, 0, &pIStorage);
  177.     if (FAILED(hr)) return NULL;
  178.  
  179.     hr = pIStorage->OpenStream("\005SummaryInformation", NULL,
  180.                         STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  181.  
  182. #endif
  183.     if (FAILED(hr)) goto ReleaseStorage;
  184.  
  185.     LISet32(li, 0);
  186.     hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  187.     if (hr != NOERROR) goto ReleaseStream;
  188.  
  189.     hr = pIStream->Read(&PropHeader, 28, &ulBytesRead);
  190.     if (hr != NOERROR || ulBytesRead != 28) goto ReleaseStream;
  191.  
  192.     if (PropHeader.byteOrder != 0xFFFE) goto ReleaseStream;
  193.     if (PropHeader.wFormat != 0) goto ReleaseStream;
  194.  
  195.     for (i = 0; i < PropHeader.cSections; i++) {
  196.         hr = pIStream->Read(&FIDAndOffset, 20, &ulBytesRead);
  197.         if (hr != NOERROR || ulBytesRead != 20) goto ReleaseStream;
  198.         if (FIDAndOffset.dwords[0] == 0XF29F85E0 && 
  199.             FIDAndOffset.dwords[1] == 0X10684FF9 &&
  200.             FIDAndOffset.dwords[2] == 0X000891AB &&
  201.             FIDAndOffset.dwords[3] == 0XD9B3272B) break;
  202.     }
  203.     if (i >= PropHeader.cSections) goto ReleaseStream;
  204.  
  205.     LISet32(li, FIDAndOffset.dwOffset);
  206.     hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  207.     if (hr != NOERROR) goto ReleaseStream;
  208.  
  209.     hr = pIStream->Read(&dwBytesInSection, 4, &ulBytesRead);
  210.     if (hr != NOERROR || ulBytesRead != 4) goto ReleaseStream;
  211.                                             
  212.     hglb = GlobalAlloc(GPTR, dwBytesInSection);
  213.     if (hglb == NULL) goto ReleaseStream; 
  214.     lpSumInfo = (LPSUMINFO) GlobalLock(hglb);
  215.     if (lpSumInfo == NULL) goto Free;
  216.  
  217.     hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  218.     if (hr != NOERROR) goto Unlock;
  219.  
  220.     hr = pIStream->Read(lpSumInfo, dwBytesInSection, &ulBytesRead);
  221.     if (hr != NOERROR || ulBytesRead > dwBytesInSection) goto Unlock;
  222.     // tbd: dwBytesInSection is long by 4 bytes for some Excel 5.0 files, so just
  223.     // check that ulBytesRead is <= dwBytesInSection and not that they are equal
  224.  
  225.     GlobalUnlock(hglb);
  226.  
  227.     goto ReleaseStream;  
  228.  
  229. Unlock:
  230.     GlobalUnlock(hglb);
  231.  
  232. Free:   
  233.     GlobalFree(hglb);
  234.     hglb = NULL;
  235.  
  236. ReleaseStream:                   
  237.     pIStream->Release();
  238.  
  239. ReleaseStorage:
  240.     pIStorage->Release();
  241.  
  242.     return hglb;       
  243. }
  244.  
  245. ///////////////////////////////////////////////////////////////////////////
  246. extern "C" void DLLEXPORT SumInfoCloseFile(HANDLE hSumInfo)
  247. {
  248.     GlobalFree(hSumInfo);
  249. }
  250.  
  251. ///////////////////////////////////////////////////////////////////////////
  252. extern "C" BOOL DLLEXPORT SumInfoGetString(HANDLE hSumInfo,
  253.                                            DWORD  pid,
  254.                                            LPSTR  lpStr,
  255.                                            WORD   cbStr)
  256. {
  257.     LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
  258.     if (lpProp == NULL) return FALSE;
  259.     if (lpProp->vtType != VT_LPSTR) return FALSE;
  260.     int len = (int) lpProp->vtValue.vtBSTR.cBytes;
  261.     if (len > cbStr) len = cbStr;
  262.     if (len <= 0) {
  263.         *(lpStr) = '\0';
  264.     }
  265.     else {
  266.         lstrcpyn(lpStr, lpProp->vtValue.vtBSTR.ch, len);
  267.         *(lpStr + len - 1) = '\0'; // len includes terminating null
  268.     }
  269.     return TRUE;
  270. }
  271.  
  272. ///////////////////////////////////////////////////////////////////////////
  273. extern "C" BOOL DLLEXPORT SumInfoGetLong(HANDLE       hSumInfo,
  274.                                                    DWORD        pid,
  275.                                                    LPLONG       lpLong)
  276. {
  277.     LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
  278.     if (lpProp == NULL) return FALSE;
  279.     if (lpProp->vtType != VT_I4) return FALSE;
  280.     *lpLong = lpProp->vtValue.vtLong;
  281.     return TRUE;
  282. }
  283.  
  284. ///////////////////////////////////////////////////////////////////////////
  285. extern "C" BOOL DLLEXPORT SumInfoGetTime(HANDLE    hSumInfo,
  286.                                                    DWORD        pid,
  287.                                                    LPWORD       yr,
  288.                                                    LPWORD       mon,
  289.                                                    LPWORD       day,
  290.                                                    LPWORD       hr,
  291.                                                    LPWORD       min,
  292.                                                    LPWORD       sec)
  293. {                                                       
  294.     struct {
  295.         unsigned int day : 5;
  296.         unsigned int mon : 4;
  297.         unsigned int yr  : 7;
  298.     } DosDate;
  299.     struct {
  300.         unsigned int sec2 : 5;
  301.         unsigned int min  : 6;
  302.         unsigned int hr   : 5;
  303.     } DosTime; 
  304.     BOOL fBefore1980;
  305.  
  306.     #define JAN1980_HIGH 0x01A8E79F
  307.     #define JAN1980_LOW  0xE1D58000
  308.  
  309.     LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
  310.     if (lpProp == NULL) return FALSE;
  311.     if (lpProp->vtType != VT_FILETIME) return FALSE;
  312.  
  313.         // If time < Jan 1, 1980, then add FILETIME of 1980/01/01 00:00:00.
  314.         // This is necessary for CoFileTimeToDosDateTime to work.
  315.     if (lpProp->vtValue.vtTime.dwHighDateTime < JAN1980_HIGH) {
  316.         lpProp->vtValue.vtTime.dwLowDateTime += JAN1980_LOW;
  317.         lpProp->vtValue.vtTime.dwHighDateTime += JAN1980_HIGH;
  318.         if (lpProp->vtValue.vtTime.dwLowDateTime < JAN1980_LOW)
  319.             lpProp->vtValue.vtTime.dwHighDateTime++; // overflow
  320.         fBefore1980 = TRUE;
  321.     }
  322.     else fBefore1980 = FALSE;
  323.  
  324.     if (!CoFileTimeToDosDateTime(&lpProp->vtValue.vtTime,
  325.                                  (LPWORD) &DosDate, (LPWORD) &DosTime))
  326.         return FALSE;
  327.  
  328.     *yr  = (WORD) (DosDate.yr + 1980);
  329.     *mon = (WORD) DosDate.mon;
  330.     *day = (WORD) DosDate.day;
  331.     *hr  = (WORD) DosTime.hr;
  332.     *min = (WORD) DosTime.min;
  333.     *sec = (WORD) (DosTime.sec2 * 2);
  334.  
  335.     if (fBefore1980) {
  336.             // Suppose edittime is actually 1 day, 3 hours.
  337.             // Then Y/M/D will be 1980/1/2 at this point.
  338.             // Which should be tranlated to 0/0/1.
  339.             // The code below also handles cases where edittime > 1 month or even 1 year.
  340.         *yr = *yr - 1980;
  341.         *mon = *mon - 1;
  342.         *day = *day - 1;
  343.         if (*mon == 0 && *yr > 0) {
  344.             (*yr)--;
  345.             *mon = 12;
  346.         }
  347.         if (*day == 0 && *mon > 0) {
  348.             (*mon)--;
  349.             switch (*mon) {
  350.                 case  1: *day = 31; break;
  351.                 case  2: *day = 28; break;
  352.                 case  3: *day = 31; break;
  353.                 case  4: *day = 30; break;
  354.                 case  5: *day = 31; break;
  355.                 case  6: *day = 30; break;
  356.                 case  7: *day = 31; break;
  357.                 case  8: *day = 31; break;
  358.                 case  9: *day = 30; break;
  359.                 case 10: *day = 31; break;
  360.                 case 11: *day = 30; break;
  361.                 case 12: *day = 31; break;
  362.             }
  363.         }
  364.     }
  365.     return TRUE;
  366. }
  367.  
  368. ///////////////////////////////////////////////////////////////////////////
  369. LPPROPVALUE FindProperty(HANDLE hSumInfo, DWORD pid)
  370. {
  371.     LPPROPVALUE lpProp;
  372.     DWORD i;
  373.     LPSUMINFO lpSumInfo = (LPSUMINFO) GlobalLock(hSumInfo);
  374.     if (lpSumInfo == NULL) return FALSE;
  375.     for (i = 0; i < lpSumInfo->cProps; i++) {
  376.         if (lpSumInfo->aProps[i].propID == pid) {
  377.             lpProp = (LPPROPVALUE) ((LPBYTE) lpSumInfo + lpSumInfo->aProps[i].dwOffset);
  378.             GlobalUnlock(hSumInfo);
  379.             return lpProp;
  380.         }
  381.     }                      
  382.     GlobalUnlock(hSumInfo);
  383.     return NULL;
  384. }
  385.